package org.dromara.quickswing.ui.app;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.CharSequenceUtil;
import org.dromara.quickswing.QSApplication;
import org.dromara.quickswing.constant.QSOs;
import org.dromara.quickswing.ui.QSActionRegistry;
import raven.toast.Notifications;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.lang.reflect.Method;
import java.util.ResourceBundle;

import static javax.swing.JOptionPane.ERROR_MESSAGE;
import static javax.swing.JOptionPane.INFORMATION_MESSAGE;

/**
 * @author Jin
 */
public abstract class QSWidget<P extends QSPrefs> extends JFrame implements QSApplication {

    private JDialog aboutDialog;
    private String language;
    private String theme;
    private final QSContext<? extends QSWidget<P>, P> context;
    private final P prefs;
    private static ResourceBundle bundle;
    private final QSActionRegistry actionRegistry;
    private int mouseX;
    private int mouseY;

    protected QSWidget(QSContext<? extends QSWidget<P>, P> context, String title, P prefs) throws HeadlessException {
        super(title);
        this.context = context;
        this.prefs = prefs;
        this.actionRegistry = new QSActionRegistry();
        this.initializeComponents();
        this.initializeActions();
        Notifications.getInstance().setJFrame(this);
    }

    protected void initializeMouseListener() {
        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                mouseX = e.getX();
                mouseY = e.getY();
            }
        });
        this.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                int newX = getLocation().x + e.getX() - mouseX;
                int newY = getLocation().y + e.getY() - mouseY;
                setLocation(newX, newY);
            }
        });
    }

    protected void initializeActions() {

    }

    public String $tr(String key) {
        Assert.notNull(bundle);
        return bundle.getString(key);
    }

    private void initializeComponents() {
        this.initializeResourceBundle();
    }

    public void registerAction(String key, Action action) {
        actionRegistry.addAction(key, action);
    }

    public void registerAction(JComponent component, QSAction<?> action) {
        InputMap inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        actionRegistry.fillInputMap(action, inputMap);
        ActionMap actionMap = component.getActionMap();
        actionRegistry.fillActionMap(action, actionMap);
    }

    public void registerAction(QSAction<?> action) {
        InputMap inputMap = this.rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        actionRegistry.fillInputMap(action, inputMap);
        ActionMap actionMap = this.rootPane.getActionMap();
        actionRegistry.fillActionMap(action, actionMap);
    }

    public Action getAction(String key) {
        return actionRegistry.getAction(key);
    }


    public void fillActionMap(String key, ActionMap actionMap) {
        actionRegistry.fillActionMap(key, actionMap);
    }


    public void fillInputMap(String key, InputMap inputMap) {
        actionRegistry.fillInputMap(key, inputMap);
    }

    private void initializeResourceBundle() {
        String resourceBundlePath = prefs.getResourceBundlePath();
        if (CharSequenceUtil.isNotEmpty(resourceBundlePath) && bundle == null) {
            try {
                Class<?> thisClass = this.getClass();
                Class<?> dynamicBundleClass = thisClass.getClassLoader().loadClass("com.intellij.DynamicBundle");
                Method cachedGetBundleMethod = dynamicBundleClass.getMethod("getBundle", String.class, Class.class);
                bundle = (ResourceBundle) cachedGetBundleMethod.invoke(null, resourceBundlePath, thisClass);
            } catch (Exception e) {
                bundle = ResourceBundle.getBundle(resourceBundlePath);
            }
        }
    }

    protected void preCreateActions(P prefs, SplashScreen splashScreen) {
    }

    protected void preMenuBarInit(P prefs, SplashScreen splashScreen) {

    }

    public QSContext<? extends QSWidget<P>, P> getContext() {
        return this.context;
    }

    public P getPrefs() {
        return this.prefs;
    }

    @Override
    public void doExit() {
        dispose();
        System.exit(0);
    }

    @Override
    public void displayException(Throwable throwable) {
        displayException("错误", throwable);
    }

    @Override
    public void displayException(String title, Throwable throwable) {
        JOptionPane.showMessageDialog(this, throwable.getMessage(), title, ERROR_MESSAGE);
    }

    @Override
    public void displayMessage(String title, String message) {
        JOptionPane.showMessageDialog(this, message, title, INFORMATION_MESSAGE);
    }

    @Override
    public JDialog getAboutDialog() {
        return aboutDialog;
    }

    @Override
    public String getLanguage() {
        return language;
    }

    @Override
    public String getTheme() {
        return theme;
    }

    @Override
    public QSOs getOS() {
        return QSOs.get();
    }

    @Override
    public ResourceBundle getResourceBundle() {
        return bundle;
    }
}